﻿using AutoMapper;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using MyCommon.Helper;
using MyCommon.HttpContextUser;
using MyExtension.Authorizations;
using MyIServices;
using MyModels;
using MyModels.Models;
using MyModels.ViewModels;
using MyServices;
using System.IdentityModel.Tokens.Jwt;
using System.Linq.Expressions;

namespace MyApi.Controllers
{
    /// <summary>
    /// 用户控制器
    /// </summary>
    [Route("api/[controller]/[action]")]
    [ApiController]
    [Authorize("Permission")]
    public class UserController : BaseApiController
    {
        private readonly ISysUserInfoServices _sysUserInfo;
        private readonly IUserRoleService _userRoleService;
        private readonly IRoleService _roleService;
        private readonly IDepartmentService _departmentService;
        private readonly IRoleModulePermissionService _roleModulePermissionService;
        private readonly IPermissionService _permissionService;
        private readonly IMapper _mapper;
        private readonly IUser _user;
        private readonly ILogger<UserController> _logger;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="sysUserInfo"></param>
        /// <param name="userRoleService"></param>
        /// <param name="roleService"></param>
        /// <param name="departmentService"></param>
        public UserController(ISysUserInfoServices sysUserInfo, IUserRoleService userRoleService, 
            IRoleService roleService, IDepartmentService departmentService,
            IRoleModulePermissionService roleModulePermissionService,
            IPermissionService permissionService,
            IMapper mapper, IUser user,ILogger<UserController> logger)
        {
            _sysUserInfo = sysUserInfo;
            _userRoleService = userRoleService;
            _roleService = roleService;
            _departmentService = departmentService;
            _roleModulePermissionService = roleModulePermissionService;
            _permissionService = permissionService;
            _mapper = mapper;
            _user = user;
            _logger = logger;
        }

        /// <summary>
        /// 根据token获取用户信息 【无权限】
        /// </summary>
        /// <param name="token"></param>
        /// <returns></returns>
        [HttpGet]
        [AllowAnonymous]
        public async Task<MessageModel<SysUserInfoDto>> GetInfoByToken(string token)
        {
            var data = new MessageModel<SysUserInfoDto>();
            if (!string.IsNullOrEmpty(token))
            {
                var tokenModel = JwtToken.SerializeToken(token);
                if (tokenModel != null && tokenModel.Uid > 0)
                {
                    var userInfo = await _sysUserInfo.QueryById(tokenModel.Uid);
                    var model = new SysUserInfoDto()
                    {
                        uId = userInfo.Id,
                        uRealName = userInfo.RealName!,
                    };

                    #region Permission
                    var roles = await _userRoleService.Query(d => d.IsDeleted == false && d.UserId == tokenModel.Uid);
                    var roleIds = roles.Select(d => d.RoleId.ObjToLong()).Distinct().ToList();
                    if (roleIds.Any())
                    {
                        var pids = (await _roleModulePermissionService.Query(d => d.IsDeleted == false && roleIds.Contains(d.RoleId)))
                                    .Select(d => d.PermissionId.ObjToLong()).Distinct();
                        if (pids.Any())
                        {
                            var rolePermissionModules = (await _permissionService.Query(i => pids.Contains(i.Id))).OrderBy(c => c.OrderSort);

                            var resData = rolePermissionModules.Where(i => i.IsDeleted == false).OrderBy(i => i.Id).ToList();

                            model.Permissions = resData.Select(i =>
                            {
                                return new Permissions
                                {
                                    Id = i.Id,
                                    Pid = i.Pid,
                                    Code = i.Code,
                                    Icon = i.Icon,
                                    Name = i.Name,
                                    IsButton = i.IsButton,
                                    IsHide = i.IsHide.Value,
                                    Func = i.Func
                                };
                            }).ToList();
                        }
                    }
                    #endregion

                    if (userInfo != null) {
                        data.data = model;// _mapper.Map<SysUserInfoDto>(userInfo);
                        data.success = true;
                        data.message = "获取成功";
                    }
                }
            }
            return data;
        }

        /// <summary>
        /// 获取用户列表
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public async Task<MessageModel<PageModel<SysUserInfo>>> Get(int page = 1, int pageSize = 10, string key = "")
        {
            Expression<Func<SysUserInfo, bool>> expression = a => a.IsDeleted != true && (a.LoginName != null && a.LoginName.Contains(key));
            PageModel<SysUserInfo> data = new PageModel<SysUserInfo>();

            var list = await _sysUserInfo.QueryPage(expression, page, pageSize, " Id desc ");

            var allUserRoles = await _userRoleService.Query(i => i.IsDeleted == false);
            var allRoles = await _roleService.Query(i => i.IsDeleted == false);
            var allDepartment = await _departmentService.Query(i => i.IsDeleted == false);

            var sysUserInfos = list.Data;
            foreach (var sysUserInfo in sysUserInfos)
            {
                var currentUserRoles = allUserRoles.Where(i => i.UserId == sysUserInfo.Id).Select(i => i.RoleId).ToList();
                sysUserInfo.RIDs = currentUserRoles;
                sysUserInfo.RoleNames = allRoles.Where(i => currentUserRoles.Contains(i.Id)).Select(i => i.Name).ToList()!;
                var departmentNameAndIds = GetFullDepartmentName(allDepartment, sysUserInfo.DepartmentId!.Value);
                sysUserInfo.DepartmentName = departmentNameAndIds.Item1;
                sysUserInfo.Dids = departmentNameAndIds.Item2;
            }
            list.Data = sysUserInfos;
            return Success(list);
        }

        /// <summary>
        /// 根据部门集合获取 指定部门及其下级的部门名称 和 所有父节点id集合
        /// </summary>
        /// <param name="departmentList">部门集合</param>
        /// <param name="did">部门id</param>
        /// <returns></returns>
        private (string, List<long>) GetFullDepartmentName(List<Department> departmentList, long did)
        {
            var model = departmentList.FirstOrDefault(i => i.Id == did);
            if (model == null) return ("", new List<long>());
            var pids = model.CodeRelationship.TrimEnd(',').Split(',').Select(d => d.ObjToLong()).ToList();
            pids.Add(model.Id);
            var pNames = departmentList.Where(i => pids.Contains(i.Id)).Select(i => i.Name).ToList();
            var fullName = string.Join('/', pNames);
            return (fullName, pids);
        }

        /// <summary>
        /// 添加用户信息
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<MessageModel<string>> Post(UserDto dto)
        {
            dto.LoginPwd = MD5Helper.MD5Encrypt32(dto.LoginPwd);
            // dto.RealName = _user.UserName;
            var res = await _sysUserInfo.Add(_mapper.Map<SysUserInfo>(dto));
            return res > 0 ? Success(res.ToString(), "添加成功") : Fail("添加失败");
        }

        /// <summary>
        /// 更新数据
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpPut]
        public async Task<MessageModel<string>> Put(UserDto dto)
        {
            var data = new MessageModel<string>();
            var oldUser = await _sysUserInfo.QueryById(dto.Id);
            if (oldUser is not { Id:>0}) {
                return Fail<string>("用户不存在或已被删除");
            }
            try
            {
                if (dto.LoginPwd != oldUser.LoginPwd) { 
                    oldUser.CriticalModifyTime= DateTime.Now;
                }
                _mapper.Map(dto,oldUser);

                // 无论是 add or update 先删除当前用户的全部 U_R 关系
                var userRoles = await _userRoleService.Query(u => u.UserId == oldUser.Id);
                if (userRoles.Any())
                {
                    var ids = userRoles.Select(x => x.Id.ToString()).ToArray();
                    var isAllDelete = await _userRoleService.DeleteByIds(ids);
                    if (!isAllDelete) return Fail("删除用户角色关系异常");
                }

                // 然后在执行添加操作
                if (dto.Rids.Count > 0) { 
                    var userRoleAdd = new List<UserRole>();
                    dto.Rids.ForEach(rid => { userRoleAdd.Add(new UserRole(oldUser.Id, rid)); });

                    var oldRoleIds = userRoles.Select(i=>i.RoleId).OrderBy(i=>i).ToArray();
                    var newRoleIds = userRoleAdd.Select(i=>i.RoleId).OrderBy(i=>i).ToArray();
                    if (!oldRoleIds.SequenceEqual(newRoleIds)) oldUser.CriticalModifyTime = DateTime.Now;

                    await _userRoleService.Add(userRoleAdd);
                }

                var res = await _sysUserInfo.Update(oldUser);
                return res ? Success(oldUser.Id.ToString(), "更新成功") : Fail("更新失败");
            }
            catch (Exception ex)
            {
                _logger.LogError(ex,ex.Message);
                return Fail("程序异常");
            }
        }

        /// <summary>
        /// 删除数据
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [HttpDelete]
        public async Task<MessageModel<string>> Delete(long id)
        {
            if (id <= 0) return Fail("参数错误");
            var model = await _sysUserInfo.QueryById(id);
            model.IsDeleted = true;
            var res = await _sysUserInfo.Update(model);
            return res ? Success(model.Id.ToString(), "删除成功") : Fail("删除失败");
        }
    }

    
}
